package edu.siu.math.egut.util;

import java.io.Serializable;

/** 
 * This class models an element of the maximal torus of a simply-connected split simple group of 
 * one of the five exceptional types.  (More precisely, we take our groups to be equipped at
 * the outset with a fixed maximal torus as well as a choice of base for the corresponding 
 * root system.  This class models an element of that particular maximal torus, and does so 
 * in a manner which makes use of that choice of base.)  
 * 
 * For the convenience of the user, we recall that in a simply-connected group, every element 
 * of a maximal torus may be expressed as a product of elements of the form \alpha^{\vee}(y)
 * where \alpha^\vee denotes the coroot associated to some simple root alpha.
 * 
 * We also make use of the numbering of the simple roots as in LiE.  This if t is a toral 
 * element which represents
 * 
 * \alpha_1^\vee (t_1) ... \alpha_{rank}^\vee (t_{rank}), 
 * 
 * then t.get(i) returns t_i.
 * 
 * The elements t_i, which is treated as an object in egut class RationalFunction.  
 * 
 * @author Joseph Hundley
 *
 */

public class Toral implements Serializable{

    private static final long serialVersionUID = 289L;
  
    private RationalFunction[] data;
    final private Group g;
    
    public static Toral update( Toral t){
	RationalFunction[] d = t.data;
	for( int i = 1; i < d.length; i++)
	    d[i]= RationalFunction.update(d[i]);
	return new Toral( d);
    }
    
    public Toral(RationalFunction[] data) {
	super();
	this.data = data;
	g = Group.getGroup(data.length);
    }
 
   public Toral( int rank){
       this.data =new RationalFunction[rank];
       for(int i = 1; i < rank; i++)
	   data[i] = new RationalFunction(1);
       this.g =Group.getGroup(rank);
       
   }
    
    public Group getGroup() {
    return g;
}

    public RationalFunction get( int i ){
	return data[i];
    }
    
    public RationalFunction[] get(){
	
	return data;
    }
    
    public void set( int i, RationalFunction p){
    	data[i] = p;
    }
    public void set( RationalFunction [] newData){
	data = newData;
	
    }
    public void multiplyBy( Toral t){
	if(t.data.length != data.length){
	    throw new RuntimeException();
	}
	for( int i = 0; i < data.length; i++)
	    data[i] = data[i].times(t.data[i]);
	
    }
    public Toral times( Toral t){
	if(t.data.length != data.length){
	    throw new RuntimeException();
	}
	Toral answer = new Toral(this.data);
	for( int i = 0; i < data.length; i++)
	    answer.data[i] = data[i].times(t.data[i]);
	return answer;
    }
    
    public void times( int i , RationalFunction p){
	data[i]	= data[i].times(p);
	
    }
    public RationalFunction pairedWith( int[] root ){
	
	if( root.length != data.length)
	    throw new RuntimeException();

	
	RationalFunction p = new RationalFunction(1);
	
	
	for(int i =0; i< data.length; i++){
		for(int j =0; j< data.length; j++){
    
	    p = p.times(data[i].raiseTo(Group.getGroup(root.length).getCartan()[i][j]*root[j]));
		}
	}
	
	
	
	return p;
	
    }
    public String  toString(){
	StringBuffer sb = new StringBuffer("Toral(");
	for(int i =0; i< data.length; i++){
	    sb.append(data[i].toString());
	    if(i< data.length -1)
		sb.append(", ");
	}
	sb.append(")");
	return sb.toString();
    }



    public int length() {
	return data.length;
    }



    /**
     * Returns the element of class Toral which models the 
     * value a^{\vee}(r) of the coroot a^{\vee} associated
     * the the root a, when evaluated at the rational function r.
     * @param a int[], thought of as a root.
     * @param r RationalFunction
     * @return
     */
    public static Toral coroot(int[] a, RationalFunction r) {
	Toral t = new Toral(a.length);
	Group g = Group.getGroup(a.length);
	/*
	 * Class toral represents its elements with respect to 
	 * the basis of Y(T) given by the coroots a_i^\vee attached
	 * to the simple roots.  (Recall that we always assume our groups
	 * are simply connected.  This means that the simple coroots do indeed 
	 * form a basis for Y(T).)
	 * 
	 * Clearly we need to know a formula for < a^\vee, \varpi_i> 
	 * where { \varpi_i} is the basis of X(T) dual to { a_i^\vee}.
	 * 
	 * Here it is:  < a^\vee, \varpi_i> = <a, \varpi_i^\vee>.(a_i,a_i)/(a,a), 
	 * where {\varpi_i^\vee} is the basis of Y(T) \otimes_Z Q dual 
	 * to the set of simple roots.  (For all semisimple groups the set
	 * of simple roots is a basis of X(T) \otimes_Z Q.  In general, 
	 * its Z-span is a proper sublattice of X(T), and so the elements
	 * of the dual lattice do not all correspond to elements of Y(T).)
	 */
	
	for(int i =0; i< t.length(); i++)
	    t.set(i, r.raiseTo(a[i]*g.getNormSquare(i)/g.getNormSquare(a)));
	
	return t;
    }

    public boolean isIndependentOf(String s) {
	for(int i = 0; i < data.length; i++)
	    if(!data[i].isIndependentOf(s))
		return false;
	
	return true;
    }
    
    // TODO equip this class with a toTeX method
    
    /**
     * @param i index of a simple reflection
     * @return this * ( a_i( this) )^{-1}.
     */
    public Toral reflectBy(int i){
	if( i < 1 || i > g.getRank())
	    throw new RuntimeException("Attempt to act on toral by Simple reflection with index out of range.");
	
	Toral answer = this.times(
		coroot(g.getPositiveRoots()[i-1], 
			this.pairedWith(g.getPositiveRoots()[i-1]).inverse()));
	
	
	return answer;
    }
    
    public Toral imageUnder( int weylAsInt ){
	Toral answer =this;
	
	while( weylAsInt > 0){
	    int i = weylAsInt%10;
	    weylAsInt = weylAsInt/10;
	    answer = answer.reflectBy(i);
	}	
	
	return answer;
    }
    
    public void replace( String variable, Polynomial replacement) throws BadSubstitutionException{
	for( int i = 0; i< data.length; i++)
	    data[i]= data[i].replace(variable, replacement);
	
    }
                      

}
